package com.sikaryofficial.workbench.utils.excel.converter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.sikaryofficial.common.core.utils.SpringUtils;
import com.sikaryofficial.workbench.external.DictService;
import com.sikaryofficial.workbench.utils.excel.annotation.ExcelDict;
import com.sikaryofficial.workbench.utils.excel.utils.StringValueConverter;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 从 ExcelDict 中获取字典信息，并进行转换
 * @param <T>
 */
public abstract class AbstractDictStringConverter<T> implements Converter<T>, StringValueConverter<T> {

    private final LoadingCache<String, Map<String, String>> cache;

    protected AbstractDictStringConverter() {
        cache = Caffeine.newBuilder()
                //最后一次写入后经过固定时间过期
                .expireAfterWrite(60, TimeUnit.SECONDS)
                //maximumSize=[long]: 缓存的最大条数
                .maximumSize(1000)
                .build(key -> {
                    DictService dictService = SpringUtils.getBean(DictService.class);
                    return dictService.getValueToLabel(key);
                });
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public T convertToJavaData(ReadConverterContext<?> context) throws Exception {
        ReadCellData<?> readCellData = context.getReadCellData();
        String stringValue = readCellData.getStringValue();

        Field field = context.getContentProperty().getField();
        ExcelDict excelEnum = getExcelDictAnnotation(field);
        Map<String, String> map = cache.get(excelEnum.value());
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue().equals(stringValue)) {
                return fromStr(entry.getKey());
            }
        }
        if (excelEnum.errorOnMissMatch()) {
            throw new RuntimeException("未知数值：" + stringValue);
        }
        return null;
    }

    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<T> context) throws Exception {
        T value = context.getValue();
        Field field = context.getContentProperty().getField();
        ExcelDict excelEnum = getExcelDictAnnotation(field);
        Map<String, String> code2TextMap = cache.get(excelEnum.value());
        return new WriteCellData<>(code2TextMap.getOrDefault(toStr(value), ""));
    }

    private ExcelDict getExcelDictAnnotation(Field field) {
        Annotation[] annotations = field.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof ExcelDict) {
                return (ExcelDict) annotation;
            }
        }
        throw new RuntimeException("ExcelDictConverter: ExcelDict not found");
    }

}
